//
//  BOLL.swift
//  GomroClient
//
//  Created by apple on 2021/6/13.
//  Copyright © 2021 cn.gomro.app. All rights reserved.
//

import Foundation


/// BOLL
/// https://blog.csdn.net/weixin_43123805/article/details/106373485
struct BOLL {
    
    enum kpiType:String {
        case up = "up"
        case mid = "mid"
        case low = "low"
    }
    
    func calcBOLLFor(Data d:[[String:Any]],
                     andNumber n:Int = 26,
                     withP p:Int = 2) -> [String:[Double]] {
        
        var arrBollTop = [Double]()
        var arrBollMid = [Double]()
        var arrBollBottom = [Double]()
        
        for i in 0..<d.count  {
            if i < n - 1 {
                continue
            }
            
            let _mid = calcMAFor(Data: d, andIndex: i, withNumber: n)
            arrBollMid.append(_mid)
            
            let std = calcSTDFor(Data: d, andIndex: i, withNumber: n)
            arrBollTop.append(_mid + Double(p) * std)
            arrBollBottom.append(_mid - Double(p) * std)
        }
        
        return [
            BOLL.kpiType.up.rawValue:arrBollTop,
            BOLL.kpiType.mid.rawValue:arrBollMid,
            BOLL.kpiType.low.rawValue:arrBollBottom
        ]
    }
}


extension BOLL {
    
    
    /// 算术平均计算函数
    /// - Parameters:
    ///   - d: [[String:Any]]
    ///   - index: Int
    ///   - n: Int
    ///   - f: String
    /// - Returns: Double
    private func calcMAFor(Data d:[[String:Any]],
                           andIndex index:Int,
                           withNumber n:Int,
                           andFile f:String = "Close") -> Double {
        
        var temp:Double = 0
        for j in (index - (n - 1))...index where j < d.count && j >= 0 {
            temp = temp + Double("\(d[j][f] ?? 0.0)")!
        }
        
        return temp / Double(n)
    }
    
    
    /// 标准差计算函数
    /// 标准差STD：M日的（C－MA）的两次方之和除以M的平方根 == 所有数减去平均值，它的平方和除以数的个数（【文华公式采用：个数减一】)，再把所得值开根号，就是1/2次方，得到的数就是这组数的标准差。
    /// - Parameters:
    ///   - d: [[String:Any]]
    ///   - index: Int
    ///   - n: Int
    /// - Returns: Double
    private func calcSTDFor(Data d:[[String:Any]],
                            andIndex index:Int,
                            withNumber n:Int,
                            andFile f:String = "Close") -> Double {
        
        var temp:Double = 0
        let ma = self.calcMAFor(Data: d, andIndex: index, withNumber: n, andFile: f)
        
        for j in (index - (n - 1))...index where j < d.count && j >= 0 {
            temp = temp + pow((Double("\(d[j][f] ?? 0.0)")! - ma), 2)
        }
        
        return sqrt(temp / Double(n - 1))
    }
}
